package com.yh.csx.bsf.flow.engine.state;

import com.fasterxml.jackson.core.type.TypeReference;

import com.yh.csx.bsf.core.base.Ref;
import com.yh.csx.bsf.core.util.JsonUtils;
import com.yh.csx.bsf.flow.engine.api.CommonApi;
import com.yh.csx.bsf.flow.provider.enums.FlowStateEnum;
import com.yh.csx.bsf.flow.core.base.*;
import com.yh.csx.bsf.flow.core.db.DbHelper;
import com.yh.csx.bsf.flow.core.util.XmlUtil;
import com.yh.csx.bsf.flow.dao.dal.*;

import com.yh.csx.bsf.flow.dao.model.auto.t_approve_log_model;

import com.yh.csx.bsf.flow.dao.model.auto.t_user_model;
import com.yh.csx.bsf.flow.engine.api.UserApi;
import lombok.*;
import lombok.extern.slf4j.Slf4j;

import java.util.*;


/**
 * @author: chejiangyi
 * @version: 2019-10-24 09:21
 * 状态机引擎
 **/
@Data
@Slf4j
public class StateEngine extends BaseFlow {
    protected Map<String,Variable> flowVariables;
    protected List<Model.Node> modelNode;
    protected Map<String,BaseNode> nodes;

    public StateEngine(){

    }

    private void init(int flowid){
        val flowmodel = DbHelper.get((c)-> new t_flow_dal().get(c,flowid));
        val flowVariablesList = JsonUtils.deserialize(flowmodel.flow_variable_json, new TypeReference<List<Variable>>() {});
        val model = DbHelper.get((c)-> new t_model_dal().get(c,flowmodel.model_id));
        val modelNodeList = XmlUtil.deserialize(model.getXml(), Xml.class).getNodes();
        flowVariables = new HashMap<>();

        flowVariablesList.forEach(c->{
            flowVariables.put(c.getKey(),c);
        });
        nodes = new HashMap<>();
        modelNodeList.forEach(c->{
            nodes.put(c.getTitle(),NodeFactory.create(flowVariables,c,nodes));
        });
    }

    public void flow(int flowid){
        try {
            DbHelper.transaction(() -> {
                init(flowid);
                val node = nodes.get("开始");
                if (node == null) {
                    throw new StateEngineException(flowid,"未找到流程节点" + "开始");
                }
                node.flow(flowid);
            });
        }catch (Exception e){
            logFlowError(flowid,e);
            throw e;
        }
    }

    public void reflow(int flowid,String userno,String remark){
        try
        {
            var user = checkUser(userno);
            changeNode(flowid,"开始",userno,"重新发起流程",remark);
        }catch (Exception e){
            logFlowError(flowid,e);
            throw e;
        }
    }

    public void doTask(int taskid,String userno, String approveResult,String remark,List<Variable> variables){
        Ref<Integer> flowid = new Ref<>(0);
        try {
            var user = checkUser(userno);
            DbHelper.transaction(() -> {
                val task = getTaskModel(taskid);
                flowid.setData(task.flow_id);
                init(task.flow_id);
                val node = nodes.get(task.flow_approve_node);
                if (node == null) {
                    throw new StateEngineException(task.flow_id,"未找到流程节点" + task.flow_approve_node);
                }
                if (node instanceof ManNode) {
                    ((ManNode) node).doTask(taskid, userno, approveResult, remark, variables);
                } else {
                    throw new StateEngineException(task.flow_id,"当前任务在非人工节点,数据异常");
                }
            });
        }catch (Exception e){
            logFlowError(flowid.getData(),e);
            throw e;
        }
    }

    public void triggerTimeout(int taskid){
        Ref<Integer> flowid = new Ref<>(0);
        try
        {
            DbHelper.transaction(()->{
                val task = getTaskModel(taskid);
                flowid.setData(task.flow_id);
                init(task.flow_id);
                val node = nodes.get(task.flow_approve_node);
                if(node == null)
                {    throw new StateEngineException(task.flow_id,"未找到流程节点"+task.flow_approve_node);}
                if(node instanceof ManNode) {
                    ((ManNode)node).triggerTimeout(taskid);
                }else {
                    throw new StateEngineException(task.flow_id,"当前任务在非人工节点,数据异常");
                }
            });
        }catch (Exception e){
            logFlowError(flowid.getData(),e);
            throw e;
        }
    }

    public void close(int flowid,String userno,String remark){
        try
        {
            var user = checkUser(userno);
            DbHelper.transaction(()->{
                DbHelper.call(c->{
                    new t_task_dal().closedAllTasks(c,flowid,"系统");
                    new t_flow_dal().updateFlowState(c,flowid, FlowStateEnum.close.Value);
                    new t_approve_log_dal().add(c,new t_approve_log_model(0,flowid,0,"关闭流程",remark,"",userno,new Date(),"系统",new Date(),"系统",user.getName()));
                });
            });
        }catch (Exception e){
            logFlowError(flowid,e);
            throw e;
        }
    }

    public void closeTask(int taskid,String userno,String remark){
        Ref<Integer> flowid = new Ref<>(0);
        try
        {
            var user = checkUser(userno);
            DbHelper.transaction(()->{
                val task = getTaskModel(taskid);flowid.setData(task.flow_id);
                init(task.flow_id);
                val node = nodes.get(task.flow_approve_node);
                if(node == null)
                {    throw new StateEngineException(task.flow_id,"未找到流程节点"+task.flow_approve_node);}
                if(node instanceof ManNode) {
                    ((ManNode)node).closeTask(taskid,userno,remark);
                }else {
                    throw new StateEngineException(task.flow_id,"当前任务在非人工节点,数据异常");
                }
            });
        }catch (Exception e){
            logFlowError(flowid.getData(),e);
            throw e;
        }
    }

    public void deleteTask(int taskid,String userno,String remark){
        Ref<Integer> flowid = new Ref<>(0);
        try
        {
            var user = checkUser(userno);
            DbHelper.transaction(()->{
                val task = getTaskModel(taskid);flowid.setData(task.flow_id);
                init(task.flow_id);
                val node = nodes.get(task.flow_approve_node);
                if(node == null)
                {    throw new StateEngineException(task.flow_id,"未找到流程节点"+task.flow_approve_node);}
                if(node instanceof ManNode) {
                    ((ManNode)node).deleteTask(taskid,userno,remark);
                }else {
                    throw new StateEngineException(task.flow_id,"当前任务在非人工节点,数据异常");
                }
            });
        }catch (Exception e){
            logFlowError(flowid.getData(),e);
            throw e;
        }
    }

    public void changeNode(int flowid,String nodeTitle,String userno,String remark){
        try
        {
            var user = checkUser(userno);
            changeNode(flowid,nodeTitle,userno,"切换节点",remark);
        }catch (Exception e){
            logFlowError(flowid,e);
            throw e;
        }
    }

    private void changeNode(int flowid,String nodeTitle,String userno,String logresult,String remark){
        var user = checkUser(userno);
        DbHelper.transaction(()->{
            init(flowid);
            val node = nodes.get(nodeTitle);
            if (node == null) {
                throw new StateEngineException(flowid,"未找到流程节点" + nodeTitle);
            }
            DbHelper.call(c->{
                new t_task_dal().closedAllTasks(c,flowid,"系统");
                new t_flow_dal().updateFlowState(c,flowid, FlowStateEnum.close.Value);
                new t_approve_log_dal().add(c,new t_approve_log_model(0,flowid,0,logresult,remark,"",userno,new Date(),"系统",new Date(),"系统",user.getName()));
            });
            node.flow(flowid);
        });
    }

    public void transfer(int taskid,String userno,String remark) {
        Ref<Integer> flowid = new Ref<>(0);
        try
        {
            var user = checkUser(userno);
            DbHelper.transaction(()->{
                val task = getTaskModel(taskid);flowid.setData(task.flow_id);
                init(task.flow_id);
                val node = nodes.get(task.flow_approve_node);
                if(node == null)
                {    throw new StateEngineException(task.flow_id,"未找到流程节点"+task.flow_approve_node);}
                if(node instanceof ManNode) {
                    ((ManNode)node).transfer (taskid,userno,remark);
                }else {
                    throw new StateEngineException(task.flow_id,"当前任务在非人工节点,数据异常");
                }
            });
        }catch (Exception e){
            logFlowError(flowid.getData(),e);
            throw e;
        }
    }

    private t_user_model checkUser(String userno){
        val user = UserApi.getUser(userno);
        if(user ==null){
            throw new FlowException("用户工号:"+userno+"不存在");
        }
        return user;
    }



    public static class NodeFactory{
        public static BaseNode create(Map<String,Variable> flowVariables, Model.Node node, Map<String,BaseNode> nodes){
            BaseNode temp = null;
            if(node.getTypeEnum() == Model.TypeEnum.Start){
                temp= new StartNode();
            }else if(node.getTypeEnum() == Model.TypeEnum.Auto){
                temp= new AutoNode();
            }else if(node.getTypeEnum() == Model.TypeEnum.Man){
                temp= new ManNode();
            }else if(node.getTypeEnum() == Model.TypeEnum.End){
                temp= new EndNode();
            }
            temp.setFlowVariables(flowVariables);
            temp.setNodes(nodes);
            temp.setModelNode(node);
            return temp;
        }
    }
    



}
